# coding=utf-8
import hashlib
import re
from io import BytesIO
import qrcode
import urllib.request
import logging
from c21_qrcode.common.redis_service import SLurl
from PIL import Image
from PIL import ImageDraw
# from vulpo.scs.connection import SCSConnection
from django.conf import settings
# from c21_qrcode.common.mime import ImageMIME
from hashlib import md5
import oss2
from oss2.exceptions import NotFound


BUCKET = None
OSS2_CONF = {
    "ACCESS_KEY_ID": "LTAI6RzpoQWseWkL",
    "ACCESS_KEY_SECRET": "XPDckNaQhvGhjf1z5HD6lygSlIyq1s",
    "ENDPOINT": "",
    "BUCKET_DOMAIN": "oss-cn-beijing.aliyuncs.com",
    "BUCKET_NAME": "hold1",
    "IMAGES_PATH": "images/",
    "VIDEOS_PATH": "videos/",
    "CDN_DOMAIN": ""
}


def get_bucket():
    global BUCKET
    if not BUCKET:
        auth = oss2.Auth(OSS2_CONF['ACCESS_KEY_ID'],
                         OSS2_CONF['ACCESS_KEY_SECRET'])
        BUCKET = oss2.Bucket(auth, 'http://%s' %
                             OSS2_CONF['BUCKET_DOMAIN'],
                             OSS2_CONF['BUCKET_NAME'])
    return BUCKET


def download_to_oss(file, filename, path=OSS2_CONF['IMAGES_PATH'], MIME=None):
    """
        上传文件对象到oss
        传入:
            :url -> icon原地址
            :path -> 图片/视频在bucket的路径，例如:images/
        返回:
            return url -> oss上该对象的资源地址

        TODO:当能够"只修改token中某个字段的时候"OSS2_ENABLE提出来，不用返回source url.
    """
    # key = path + md5(file).hexdigest()
    key = path + filename
    if OSS2_CONF["CDN_DOMAIN"] != "":
        source = 'http://%s/%s' % (OSS2_CONF["CDN_DOMAIN"], key)
    else:
        source = 'http://{0}.{1}/{2}'.format(
            OSS2_CONF["BUCKET_NAME"], OSS2_CONF["BUCKET_DOMAIN"], key)
    # 关闭对象上传时，也返回source url，防止icon_url被空串替代
    bucket = get_bucket()

    headers = {'content-type': MIME} if MIME else {}
    bucket.put_object(
        key=key, data=file, headers=headers)
    print("%s上传成功" % key)

    # try:
    #     bucket.head_object(key)
    # except NotFound as e:
    #     headers = {'content-type': MIME} if MIME else {}
    #     bucket.put_object(
    #         key=key, data=file, headers=headers)
    #     print("%s上传成功" % key)
    return source


# def upload_file2s3(file, folder, filename, MIME=None):
#     """TODO: Docstring for upload_file_to_s3.

#     :file: 要上传的file
#     :returns: TODO

#     """
#     global SNS_BUCKET, S3_CONN
#     sns_bucket = SNS_BUCKET
#     try:
#         filename = sns_bucket.new_key(folder + filename)
#     except:
#         S3_CONN = SCSConnection(ACCESS_KEY, SECRET_KEY)
#         SNS_BUCKET = S3_CONN.get_bucket(S3_BUCKET)
#         sns_bucket = SNS_BUCKET
#         filename = sns_bucket.new_key(folder + filename)
#     try:
#         headers = {'content-type': MIME} if MIME else {}
#         filename.set_contents_from_file(file, headers=headers)
#     except Exception as e:
#         raise e


def circle_corder_image(im):
    '''处理图片成圆角矩形'''
    background = Image.new('RGBA', im.size, (255, 255, 255))
    x, y = im.size
    background.paste(im, (0, 0, x, y), im)
    im = background
    rad = 8  # 设置半径
    circle = Image.new('L', (rad * 2, rad * 2), 255)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2, rad * 2), fill=255)
    alpha = Image.new('L', im.size, 255)
    w, h = im.size
    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
    im.putalpha(alpha)
    return im


def add_avatar(img, avatar_url=None, avatar_border=False):
    if not avatar_url:
        avatar_url = ("http://ihold.com/wxshare.png")
    try:
        avatar_img = urllib.request.urlopen(avatar_url).read()
    except Exception as e:
        logger.error(e)
        logger.error(avatar_url)
    finally:
        avatar_img = urllib.request.urlopen(avatar_url).read()
    avatar = BytesIO(avatar_img)
    icon_avatar = Image.open(avatar)
    icon_avatar = icon_avatar.convert("RGBA")
    img_w, img_h = img.size
    factor = 2
    size_w = int(img_w / factor)
    size_h = int(img_h / factor)
    icon_w, icon_h = (96, 96)
    if icon_w > size_w:
        icon_w = size_w
    if icon_h > size_h:
        icon_h = size_h

    # 更改头像大小
    icon_avatar = icon_avatar.resize((icon_w, icon_h), Image.ANTIALIAS)
    w = int((img_w - icon_w) / 2) - 6
    h = int((img_h - icon_h) / 2) - 2
    if avatar_border:
        # 处理头像为圆角矩形
        icon_avatar = circle_corder_image(icon_avatar)
        # 打开圆角矩形底图
        border = Image.open(settings.BASE_DIR + '/border.png')
        border = border.convert('RGBA')
        border_w, border_h = border.size
        b_w = int((border_w - icon_w) / 2)
        b_h = int((border_h - icon_h) / 2)
        border.paste(icon_avatar, (b_w, b_h), mask=icon_avatar)
        img.paste(border, (w, h), border)
    else:
        img.paste(icon_avatar, (w, h), icon_avatar)
    return img


def get_qrcode(
        url, need_avatar=1, avatar_url=None, avatar_border=False,
        q_version=5, q_ec='H', q_box_size=9, q_border=1, fill_color="black"):
    '''生成二维码'''
    error_corrections = {
        'H': qrcode.constants.ERROR_CORRECT_H,
        'L': qrcode.constants.ERROR_CORRECT_L
    }
    ec = error_corrections.get(
        q_ec, qrcode.constants.ERROR_CORRECT_H)
    qr = qrcode.QRCode(
        version=q_version,
        error_correction=ec,
        box_size=q_box_size,
        border=q_border
    )
    qr.add_data(url)
    qr.make(fit=True)
    img = qr.make_image(fill_color=fill_color, back_color="white")
    img = qr.make_image()
    img = img.convert("RGBA")
    if need_avatar:
        img = add_avatar(
            img, avatar_url=avatar_url,
            avatar_border=avatar_border)

    # img_data = img.getdata()
    # colors = []
    # for i in img_data:
    #     if i[0] == 0 and i[1] == 0 and i[2] == 0:
    #         # colors.append((17, 36, 67, 0))
    #         colors.append((0, 0, 0, 0))
    #     else:
    #         colors.append(i)
    # img.putdata(colors)

    # img = img.convert('P', palette=Image.ADAPTIVE, colors=255)
    imagefile = BytesIO()  # writable object
    img.save(imagefile, format='PNG')
    imagedata = imagefile.getvalue()
    # MIME = ImageMIME().get_image_type(imagedata)
    f = BytesIO(imagedata)
    return f, 'image/png'


def __original_shorturl(url):
    '''
    算法：
    ① 将长网址用md5算法生成32位签名串，分为4段,，每段8个字符；
    ② 对这4段循环处理，取每段的8个字符, 将他看成16进制字符串与0x3fffffff(30位1)的位与操作，超过30位的忽略处理；
    ③ 将每段得到的这30位又分成6段，每5位的数字作为字母表的索引取得特定字符，依次进行获得6位字符串；
    ④ 这样一个md5字符串可以获得4个6位串，取里面的任意一个就可作为这个长url的短url地址。
    （出现重复的几率大约是n/(62^6) 也就是n/1,073,741,824，其中n是数据库中记录的条数）
    '''
    base32 = [
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
        'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
        'y', 'z',
        '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '-', '_',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
        'Y', 'Z',
    ]
    m = hashlib.md5()
    m.update(url.encode('utf-8'))
    hexStr = m.hexdigest()
    hexStrLen = len(hexStr)
    subHexLen = int(hexStrLen / 8)
    output = []
    for i in range(subHexLen):
        if i < subHexLen - 1:
            subHex = '0x' + hexStr[i * 8:(i + 1) * 8 + 1]
        else:
            subHex = '0x' + hexStr[i * 8:(i + 1) * 8] + hexStr[0]
        res = 0xFFFFFFFFF & int(subHex, 16)
        out = ''
        for j in range(6):
            val = 0x0000003F & res
            out += (base32[val])
            res = res >> 6
        output.append(out)
    return output


def shorturl(url):
    '''
    算法：
    ①从原始url中提取域名，提取数字（最多后6位）；
    ②将所得的数字与4取模，根据所得的余数决定从第一步算法中得到的4个shorturl中选取哪一个；
    ③从域名中提取特征串：一级域名中的第一个字符和后面二个辅音（如果辅音不足2个取任意前两个）；
    ④域名特征串和选定的shorturl拼接成9位字符为最终的shorturl；
    （后两个步骤是将冲突控制在一个domain内）
    '''
    match_full_domain_regex = re.compile(
        u'^(http|https)?:\/\/(([a-zA-Z0-9_\-\.]+[a-zA-Z0-9_\-]+\.[a-zA-Z0-9]+)|([a-zA-Z0-9_\-]+\.[a-zA-Z0-9]+)).*$')
    # match_full_domain_regex = re.compile(u'^(http|https)?:\/\/([a-zA-Z0-9_\-\.]+).*$')
    match_full_domain = match_full_domain_regex.match(url)
    if match_full_domain is not None:
        full_domain = match_full_domain.group(2)
    else:
        return None
    not_numeric_regex = re.compile(u'[^\d]+')
    numeric_string = not_numeric_regex.sub(r'', url)
    if numeric_string is None or numeric_string == '':
        numeric_string = '0'
    else:
        numeric_string = numeric_string[-6:]
    domainArr = full_domain.split('.')
    domain = domainArr[1] if len(domainArr) == 3 else domainArr[0]
    vowels = 'aeiou0-9'
    prefix = ''
    if len(domain) <= 3:
        prefix = domain
    else:
        prefix = re.compile(u'[%s]+' % vowels).sub(r'', domain[1:])
        prefix = '%s%s' % (domain[0], prefix[:2]) if len(
            prefix) >= 2 else domain[0:3]
    t_shorturl = __original_shorturl(url)
    shortstr = t_shorturl[int(numeric_string) % 4]
    return prefix, shortstr, t_shorturl


def only_short_url(url, pro=None):
    prefix, shortstr, t_shorturl = shorturl(url)
    if pro:
        # 呼应url分配的短链,区分项目
        prefix = pro + prefix[len(pro):]
    slurl = SLurl()
    short_url = prefix + shortstr
    while slurl.get(short_url):
        # 表明是同意long_url占用
        if url == slurl.get(short_url)['long_url']:
            break
        t_shorturl.pop(t_shorturl.index(shortstr))
        if not t_shorturl:
            break
        # 保证同一用户来每次来都能取到同一个
        shortstr = t_shorturl[0]
        short_url = prefix + shortstr
    # 把所有能取的短链都取完了,发现redis中还是有人占用,
    # 则无法满足,才用报警方式单独处理
    if not t_shorturl and slurl.get(short_url):
        error_inf = 'all_short_url repeat\r\nall_short_url:%s\r\nlong_url:%s' \
            % (str(t_shorturl), url)
        logger.error(error_inf)
        return False
    return short_url


if __name__ == '__main__':
    url = 'http://h5.t.sohu.com/user/profile/bHpoYW4wMzVAc29odS5jb20-'
    short_url = shorturl(url)
    # f = open('mime.py','r')
    # upload_file2s3(file=f, folder='baisong',
    #            filename='baisong',MIME='application/octet-stream')
